﻿using System;
using RestSharp;
using System.Web.Security;
using System.Web.WebPages;
using Ayatta.Contract.Domain;
using Ayatta.Common.Extensions;
using Ayatta.Contract.Component;
using System.Collections.Specialized;

namespace Web.Base.OnlinePays
{
    /// <summary>
    /// 支付宝支付
    /// </summary>
    internal sealed class AliPay : OnlinePay
    {
        private static string Charset
        {
            get { return "utf-8"; }
        }

        private static string SignType
        {
            get { return "MD5"; }
        }

        private static string PaymentType
        {
            get { return "1"; }
        }

        private static string SellerEmail
        {
            get { return "test@163.ocm"; }
        }

        public AliPay(PaymentPlatform platform)
            : base(platform)
        {
            Client.BaseUrl = BaseUrl = platform.GatewayUrl;
        }

        public override string GetPayUrl(PayTrade trade)
        {
            var param = new NameValueCollection();

            var orderId = trade.Id;
            var amount = trade.Amount.ToString("F2");
            var subject = "测试";
            var body = "测试1";
            var showUrl = "http://www.xx.com";

            var version = trade.Version.TimestampToString();

            param.Add("partner", Platform.MerchantId);
            param.Add("_input_charset", Charset);
            param.Add("service", "create_direct_pay_by_user");
            param.Add("payment_type", PaymentType);
            param.Add("notify_url", Platform.NotifyUrl);
            param.Add("return_url", Platform.CallbackUrl);
            param.Add("seller_email", SellerEmail);
            param.Add("out_trade_no", orderId);
            param.Add("subject", subject);
            param.Add("total_fee", amount);
            param.Add("body", body);
            param.Add("show_url", showUrl);
            //param.Add("anti_phishing_key", anti_phishing_key);
            param.Add("exter_invoke_ip", trade.IpAddress);
            param.Add("extra_common_param", version);

            param.Sort();

            param.Add("sign", CreateSign(param));
            param.Add("sign_type", SignType);

            return Platform.GatewayUrl + param.ToQueryString(true, true, true);
        }

        public override SkResult<Notification> NotityHandler(NameValueCollection nv)
        {
            var flag = VerifySign(nv);
            var now = DateTime.Now;
            var notification = new Notification(Platform.Id);
            var result = new SkResult<Notification> { Data = notification };
            if (flag)
            {
                //商户订单号
                var no = nv["out_trade_no"];
                //支付宝交易号
                var tradeNo = nv["trade_no"];
                //交易状态
                var tradeStatus = nv["trade_status"];

                var amount = nv["total_fee"].AsDecimal(0);
                var payTime = nv["gmt_payment"].AsDateTime(now);
                var version = nv["extra_common_param"].StringToTimestamp();
                var signature = nv["sign"];

                result.Extra = nv;
                result.Data = new Notification(no, amount, tradeNo, payTime, version, signature);

                if (tradeStatus == "TRADE_FINISHED" || tradeStatus == "TRADE_SUCCESS")
                {
                    notification.Token = "success";
                    result.Status = OnNotityed(notification);
                }
                else
                {
                    result.Message = "通知验证签名失败";
                }
            }
            else
            {
                result.Message = "验证签名失败";
            }
            return result;
        }

        /// <summary>
        /// 生成签名
        /// </summary>
        /// <param name="nv">待签名参数</param>
        /// <returns></returns>
        private string CreateSign(NameValueCollection nv)
        {
            var plain = nv.Sort().ToQueryString(false, true) + Platform.PrivateKey;
            var sign = FormsAuthentication.HashPasswordForStoringInConfigFile(plain, SignType);
            return sign == null ? string.Empty : sign.ToUpper();
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="nv">待验证签名参数</param>
        /// <returns></returns>
        public bool VerifySign(NameValueCollection nv)
        {
            var param = nv.Filter(new[] { "sign", "sign_type" });
            //获取返回时的签名验证结果
            var isSign = nv["sign"].ToUpper().Equals(CreateSign(param));

            //获取是否是支付宝服务器发来的请求的验证结果
            var responseTxt = "true";
            var notifyId = nv["notify_id"];
            if (!string.IsNullOrEmpty(notifyId))
            {
                var request = new RestRequest();
                request.AddParameter("service", "notify_verify");
                request.AddParameter("partner", Platform.MerchantId);
                request.AddParameter("notify_id", notifyId);
                responseTxt = Client.Execute(request).Content;
            }
            //判断responsetTxt是否为true，isSign是否为true
            //responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
            //isSign不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
            return isSign && responseTxt == "true";
        }
    }
}